#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include<iostream>
#include<unistd.h>
#include<vector>
#include<pthread.h>
#include<queue>
using namespace std;
const int N=5;
 template<class T>
class blockqueue{

     private:
       bool isfull(){ return _q.size()==N;}
       bool isempty(){ return _q.empty();}
   public: 

     blockqueue(int cap=N):_cap(cap),_csleep_num(0)
     ,_psleep_num(0){
         pthread_mutex_init(&_lock,nullptr);
         pthread_cond_init(&_ccond,nullptr);
         pthread_cond_init(&_pcond,nullptr);

     }
     void equeue(T &data) {
        //加锁：
        pthread_mutex_lock(&_lock);
        //临界区：
        while(isfull()){//防止多线程被唤醒；造成无full判断而q满了还在push
            cout<<"resource full : 生产者休眠"<<endl;
            _psleep_num++;
            pthread_cond_wait(&_pcond,&_lock);//当前行醒来；无锁需要继续争取；
            //如果抢不到就继续休眠--.>伪唤醒
            _psleep_num--;


        }
         _q.push(data);
        //pthread_mutex_unlock(&_lock);
        
        //这样也可以；不过可能有种极端情况：假设线程1解开锁了；线程2来了；此时消费者
        //休眠队列只有一个；然而线程1刚执行完要进入if；此时线程2来了被cpu调度；此时就可能
        //发生数据不一致；明明休眠队列没人了；线程1还调用了一次；
        //但是此时signal函数只是返回错误码;所以影响不大-->也就是可以在此处进行解锁
    
         if( _csleep_num>0){
            cout<<"唤醒消费者:"<<endl;
            pthread_cond_signal(&_ccond);
         }
        pthread_mutex_unlock(&_lock);//此时需要等待锁被解开；然后所有线程开始竞争
        //谁抢到锁归谁操作；可以是生产者也可以是消费者--->更建议这种解锁
     }
          
     T&Pop(){
        pthread_mutex_lock(&_lock);
            while(isempty()){//防止多线程被唤醒；造成empty判断而q空了还在pop
                cout<<"resource empty: 消费者休眠"<<endl;
            _csleep_num++;
            pthread_cond_wait(&_ccond,&_lock);
            _csleep_num--;

            }  
         T &res=_q.front();
        _q.pop();
        //也可以在这解锁；同理
        //pthread_mutex_unlock(&_lock);

        if(_psleep_num>0){
            cout<<"唤醒生产者:"<<endl;
            pthread_cond_signal(&_pcond);
        }
        pthread_mutex_unlock(&_lock);//同理
            return res;
     }
     ~blockqueue(){
        pthread_mutex_destroy(&_lock);
        pthread_cond_destroy(&_ccond);
        pthread_cond_destroy(&_pcond);

     }
  private:
   queue<T> _q;
   int _cap;
   int _csleep_num;
   int _psleep_num;
   pthread_mutex_t _lock;
   pthread_cond_t _ccond;
   pthread_cond_t _pcond;
};

